using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using wicpowerTcpTool; // 添加主命名空间引用
namespace wicpowerTcpTool.Network
{
    /// <summary>
    /// TCP服务器实现类，提供带验证功能的TCP通信服务
    /// </summary>
    /// <remarks>
    /// 主要功能：
    /// 1. 监听指定端口接收客户端连接
    /// 2. 支持密令验证机制
    /// 3. 管理多个客户端连接
    /// 4. 提供数据收发功能
    /// 
    /// 设计特点：
    /// - 线程安全设计
    /// - 支持资源释放
    /// - 提供详细事件通知
    /// - 可配置验证超时时间
    /// 
    /// 使用示例：
    /// var server = new TcpServer(8080);
    /// server.Start();
    /// </remarks>
    public class TcpServer : IDisposable
    {
        private TcpListener listener;
        private List<TcpClient> clients;
        private bool isRunning;
        private readonly IPAddress listenIP;
        private readonly int port;
        private CancellationTokenSource cancellationTokenSource;
        private bool isDisposed;
        private readonly bool requireAuth;
        private byte[] expectedTokenBytes = Array.Empty<byte>();
        private const int AuthTimeoutMs = 60000;//一分钟超时未验证通过自动断开连接
        private const int MaxConnections = 10;
        private Dictionary<TcpClient, bool> clientAuthStatus = new Dictionary<TcpClient, bool>();
        private TcpClient currentClient;
        private volatile bool isAuthenticated;

        /// <summary>
        /// 客户端连接状态变化事件
        /// </summary>
        public event EventHandler<bool> ConnectionStatusChanged;
        
        /// <summary>
        /// 接收到数据事件
        /// </summary>
        public event EventHandler<byte[]> DataReceived;
        
        /// <summary>
        /// 发生错误事件
        /// </summary>
        public event EventHandler<Exception> ErrorOccurred;
        
        /// <summary>
        /// 服务器状态变化事件
        /// </summary>
        public event EventHandler<bool> ServerStatusChanged;

        public bool IsRunning => isRunning;
        public bool IsClientConnected => clients.Any(c => c.Connected);
        public int Port => port;

        /// <summary>
        /// 构造函数，创建TCP服务器实例
        /// </summary>
        /// <param name="port">监听端口号</param>
        /// <param name="listenIP">监听IP地址，默认为任意地址(IPAddress.Any)</param>
        /// <param name="requireAuth">是否需要验证，默认为true</param>
        /// <exception cref="ArgumentOutOfRangeException">端口号无效时抛出</exception>
        public TcpServer(int port, IPAddress listenIP = null, bool requireAuth = true)
        {
            this.port = port;
            this.listenIP = listenIP ?? IPAddress.Any;
            this.isRunning = false;
            this.isDisposed = false;
            this.clients = new List<TcpClient>();
            this.requireAuth = requireAuth;
        }

        /// <summary>
        /// 启动服务器开始监听
        /// </summary>
        /// <exception cref="ObjectDisposedException">对象已释放时抛出</exception>
        /// <exception cref="SocketException">网络相关错误时抛出</exception>
        /// <remarks>
        /// 启动后会触发ServerStatusChanged事件
        /// </remarks>
        public void Start()
        {
            if (isDisposed)
                throw new ObjectDisposedException(nameof(TcpServer));

            if (isRunning)
                return;

            try
            {
                cancellationTokenSource = new CancellationTokenSource();
                var localEP = new IPEndPoint(listenIP, port);
                listener = new TcpListener(localEP);
                listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                listener.Server.ExclusiveAddressUse = false;
                listener.Start();

                isRunning = true;
                ServerStatusChanged?.Invoke(this, true);
                Task.Run(AcceptClientsAsync, cancellationTokenSource.Token);
            }
            catch (Exception ex)
            {
                isRunning = false;
                ServerStatusChanged?.Invoke(this, false);
                ErrorOccurred?.Invoke(this, ex);
                throw;
            }
        }

        /// <summary>
        /// 停止服务器运行
        /// </summary>
        /// <remarks>
        /// 会断开所有客户端连接并停止监听
        /// </remarks>
        public void Stop()
        {
            if (isDisposed || !isRunning)
                return;

            try
            {
                isRunning = false;
                cancellationTokenSource?.Cancel();

                foreach (var client in clients.ToList())
                {
                    CleanupClient(client);
                }

                listener?.Stop();
                ServerStatusChanged?.Invoke(this, false);
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
            }
        }

        /// <summary>
        /// 发送数据到所有已连接的客户端
        /// </summary>
        /// <param name="data">要发送的数据</param>
        /// <returns>表示异步操作的任务</returns>
        /// <exception cref="ObjectDisposedException">对象已释放时抛出</exception>
        /// <exception cref="InvalidOperationException">没有客户端连接时抛出</exception>
        /// <exception cref="AggregateException">发送失败时抛出</exception>
        public async Task SendDataAsync(byte[] data)
        {
            if (isDisposed)
                throw new ObjectDisposedException(nameof(TcpServer));

            if (!clients.Any(c => c.Connected))
                throw new InvalidOperationException("没有连接的客户端");

            List<Exception> errors = new List<Exception>();
            List<TcpClient> disconnectedClients = new List<TcpClient>();

            foreach (var client in clients.ToList())
            {
                if (!client.Connected)
                {
                    disconnectedClients.Add(client);
                    continue;
                }

                try
                {
                    NetworkStream stream = client.GetStream();
                    try
                    {
                        await stream.WriteAsync(data, 0, data.Length);
                        await stream.FlushAsync();
                    }
                    catch (Exception ex)
                    {
                        errors.Add(ex);
                        disconnectedClients.Add(client);
                    }
                }
                catch (Exception ex)
                {
                    errors.Add(ex);
                    disconnectedClients.Add(client);
                }
            }

            foreach (var client in disconnectedClients)
            {
                CleanupClient(client);
            }

            if (errors.Count > 0)
            {
                ErrorOccurred?.Invoke(this, new AggregateException(errors));
                if (errors.Count == clients.Count)
                {
                    throw new AggregateException(errors);
                }
            }
        }

        private async Task AcceptClientsAsync()
        {
            while (!cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    var newClient = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
                    if (clients.Count >= MaxConnections)
                    {
                        newClient.Close();
                        continue;
                    }

                    clients.Add(newClient);
                    ConnectionStatusChanged?.Invoke(this, true);
                    _ = HandleClientAsync(newClient);
                }
                catch (ObjectDisposedException) { /* 正常停止 */ }
                catch (Exception ex)
                {
                    ErrorOccurred?.Invoke(this, ex);
                }
            }
        }

        /// <summary>
        /// 将HEX字符串转换为字节数组
        /// </summary>
        /// <param name="hex">HEX格式字符串</param>
        /// <returns>转换后的字节数组</returns>
        /// <exception cref="ArgumentException">HEX字符串格式无效时抛出</exception>
        public static byte[] HexStringToBytes(string hex)
        {
            if (string.IsNullOrWhiteSpace(hex))
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] HEX字符串为空");
                return Array.Empty<byte>();
            }

            try
            {
                hex = hex.Replace("-", "").Replace(" ", "");

                if (hex.Length % 2 != 0)
                {
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] HEX字符串长度无效: {hex.Length}");
                    throw new ArgumentException("HEX字符串长度必须是偶数");
                }

                var result = new byte[hex.Length / 2];
                for (int i = 0; i < result.Length; i++)
                {
                    string byteValue = hex.Substring(i * 2, 2);
                    result[i] = Convert.ToByte(byteValue, 16);
                }

                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] HEX转换成功: {hex} -> {BitConverter.ToString(result)}");
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] HEX转换错误: {ex.Message}");
                return Array.Empty<byte>();
            }
        }

        /// <summary>
        /// 获取设置验证密令
        /// </summary>
        /// <param name="hexToken">HEX格式的密令字符串</param>
        /// <exception cref="ArgumentException">密令格式无效时抛出</exception>
        public void SetAuthToken(string hexToken)
        {
            try
            {
                expectedTokenBytes = HexStringToBytes(hexToken);
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 获取密令设置成功: {BitConverter.ToString(expectedTokenBytes)}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 获取密令设置失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 获取当前活动的客户端连接
        /// </summary>
        /// <returns>当前活动的TcpClient实例，没有则返回null</returns>
        public TcpClient GetCurrentClient()
        {
            lock (this)
            {
                return currentClient?.Connected == true ? currentClient : null;
            }
        }


        // 修改 HandleClientAsync 方法中的 WriteAsync 调用部分
        /// <summary>
        /// 处理客户端连接的核心方法(修改后版本)
        /// </summary>
        /// <param name="client">连接的TcpClient实例</param>
        /// <remarks>
        /// 主要变更：
        /// 1. 验证失败后不再立即断开连接
        /// 2. 客户端有3分钟时间持续尝试验证
        /// 3. 超时后自动断开连接
        /// 4. 验证失败会返回错误信息但不中断连接
        /// 
        /// 注意事项：
        /// - 验证超时时间由AuthTimeoutMs常量控制(默认3分钟)
        /// - 验证失败会记录详细日志
        /// - 资源释放由using语句和finally块确保
        /// </remarks>
        /// <summary>
        /// 异步处理客户端连接的整个生命周期
        /// </summary>
        /// <param name="client">连接的TcpClient实例</param>
        /// <returns>表示异步操作的任务</returns>
        /// <remarks>
        /// 方法功能：
        /// 1. 处理客户端验证流程（如果启用验证）
        /// 2. 管理客户端连接状态
        /// 3. 接收并处理客户端发送的数据
        /// 4. 触发相关事件通知
        /// 
        /// 验证流程：
        /// - 如果requireAuth为true，客户端需要在AuthTimeoutMs时间内发送正确的验证令牌
        /// - 验证失败会返回错误信息但不立即断开连接
        /// - 验证超时后自动断开连接
        /// 
        /// 数据处理：
        /// - 验证通过后持续接收客户端数据
        /// - 接收到的数据会通过DataReceived事件通知
        /// 
        /// 异常处理：
        /// - 捕获并记录所有异常
        /// - 通过ErrorOccurred事件通知异常情况
        /// - 确保资源正确释放
        /// 
        /// 示例：
        /// <code>
        /// var server = new TcpServer(8080);
        /// server.Start();
        /// // HandleClientAsync会自动被AcceptClientsAsync调用
        /// </code>
        /// </remarks>
        private async Task HandleClientAsync(TcpClient client)
        {
            var timeoutCTS = new CancellationTokenSource();
            timeoutCTS.CancelAfter(AuthTimeoutMs);
            try
            {
                var stream = client.GetStream();
                if (requireAuth)
                {
                    Console.WriteLine("========= 开始验证流程 =========");
                    if (expectedTokenBytes.Length == 0)
                    {
                        var noTokenMsg = Encoding.UTF8.GetBytes("ERROR:NO_TOKEN_SET");
                        await stream.WriteAsync(noTokenMsg, 0, noTokenMsg.Length);
                        return;
                    }
                    bool authenticated = false;
                    var startTime = DateTime.UtcNow;
                    while (!authenticated && !timeoutCTS.Token.IsCancellationRequested)
                    {
                        

                        if ((DateTime.UtcNow - startTime).TotalMilliseconds > AuthTimeoutMs)
                        {
                            Console.WriteLine("验证超时");
                            var successMsg = Encoding.UTF8.GetBytes("INFO:Verification failed or timed out");
                            await stream.WriteAsync(successMsg, 0, successMsg.Length);
                            break;
                        }

                        if (stream.DataAvailable)
                        {
                            try
                            {
                                var authBuffer = new byte[expectedTokenBytes.Length];
                                int bytesRead = await stream.ReadAsync(authBuffer, 0, authBuffer.Length);
                                Console.WriteLine($"收到验证数据: {BitConverter.ToString(authBuffer, 0, bytesRead)}");
                                if (bytesRead == expectedTokenBytes.Length &&
                                    authBuffer.Take(bytesRead).SequenceEqual(expectedTokenBytes))
                                {
                                    authenticated = true;
                                    var successMsg = Encoding.UTF8.GetBytes("INFO:Valid SecretKey");
                                    await stream.WriteAsync(successMsg, 0, successMsg.Length);
                                    Console.WriteLine("验证成功");
                                    lock (this)
                                    {
                                        currentClient = client;
                                    }
                                    lock (clientAuthStatus)
                                    {
                                        clientAuthStatus[client] = true;
                                    }
                                }
                                else
                                {
                                    var errorMsg = Encoding.UTF8.GetBytes("INFO:Invalid secretKey");
                                    await stream.WriteAsync(errorMsg, 0, errorMsg.Length);
                                    Console.WriteLine("验证失败，等待重试...");
                                }
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"验证过程中出错: {ex.Message}");
                                break;
                            }
                        }
                        else
                        {
                            // 防止 CPU 空转
                            await Task.Delay(200);
                        }
                    }
                    if (!authenticated)
                    {
                        Console.WriteLine("验证超时或失败，关闭连接");
                        try
                        {
                            var successMsg = Encoding.UTF8.GetBytes("INFO:Verification failed or timed out");
                            await stream.WriteAsync(successMsg, 0, successMsg.Length);
                        }
                        catch { }


                        client.Close();
                        return;
                    }




                }

                // 验证通过后的数据处理
                var receiveBuffer = new byte[4096];
                while (client.Connected)
                {
                    var receivedBytes = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length);
                    if (receivedBytes == 0) break;

                    var receivedData = new byte[receivedBytes];
                    Array.Copy(receiveBuffer, receivedData, receivedBytes);
                    DataReceived?.Invoke(this, receivedData);
                }
            }
            catch (OperationCanceledException)
            {
                Logger.Log($"验证超时: 客户端{client?.Client?.RemoteEndPoint}");
                Console.WriteLine("验证超时");
                try
                {
                    var stream = client.GetStream();
                    var timeoutMsg = Encoding.UTF8.GetBytes("INFO:Verification failed or timed out");
                    await stream.WriteAsync(timeoutMsg, 0, timeoutMsg.Length);
                }
                catch { }
                Logger.Log($"验证超时: 客户端{client?.Client?.RemoteEndPoint}");
                client.Close();  // <--- 新增，确保断开连接
            }
            catch (Exception ex)
            {
                Console.WriteLine($"处理客户端时出错: {ex.Message}");
                ErrorOccurred?.Invoke(this, ex);
            }
            finally
            {
                // 获取当前对象锁，确保在多线程环境下安全操作currentClient
                lock (this)
                {
                    // 检查当前处理的客户端是否是记录的当前活动客户端
                    if (currentClient == client)
                    {
                        currentClient = null;// 检查当前处理的客户端是否是记录的当前活动客户端
                    }
                }
                // 获取验证状态字典锁，确保线程安全操作clientAuthStatus
                lock (clientAuthStatus)
                {
                    clientAuthStatus.Remove(client);// 从验证状态字典中移除该客户端的验证状态
                }

                clients.Remove(client);// 从全局客户端列表中移除该客户端
                                       // 触发连接状态变化事件：
                                       // - 参数1: 事件源(this)
                                       // - 参数2: 布尔值表示是否还有连接中的客户端
                ConnectionStatusChanged?.Invoke(this, clients.Any(c => c.Connected));

                try
                {
                    // 关闭TCP连接，释放底层套接字资源
                    client.Close();
                }
                catch { }
                // 释放超时取消令牌资源
                // 确保CancellationTokenSource被正确释放，避免内存泄漏
                timeoutCTS.Dispose();
            }
        }




        /// <summary>
        /// 检查客户端是否已通过验证
        /// </summary>
        /// <param name="client">要检查的客户端实例</param>
        /// <returns>是否已通过验证</returns>
        public bool IsClientAuthenticated(TcpClient client)
        {
            try
            {
                return client != null &&
                       client.Connected &&
                       clientAuthStatus.TryGetValue(client, out var auth) &&
                       auth;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"验证异常: {ex.Message}");
                return false;
            }
        }

        private void CleanupClient(TcpClient client)
        {
            try
            {
                client.Close();
                clients.Remove(client);
                if (clients.Count == 0 || !clients.Any(c => c.Connected))
                {
                    ConnectionStatusChanged?.Invoke(this, false);
                }
            }
            catch (Exception ex)
            {
                ErrorOccurred?.Invoke(this, ex);
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <remarks>
        /// 会停止服务器并释放所有资源
        /// </remarks>
        public void Dispose()
        {
            if (isDisposed)
                return;

            Stop();
            foreach (var client in clients.ToList())
            {
                client.Dispose();
            }
            clients.Clear();
            listener?.Stop();
            cancellationTokenSource?.Dispose();

            isDisposed = true;
            GC.SuppressFinalize(this);
        }

        TcpServer()
        {
            Dispose();
        }
    }
}